import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

import java.io.ByteArrayOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;

import javax.crypto.Cipher;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * 非对称（RSA）加密
 * 
 */
public class AsymmetricCrypto implements SecurityInc {

	private KeyPair keypair = null;

	private PublicKey publicKey = null;

	private PrivateKey privateKey = null;

	private Cipher ecipher = null;

	private Cipher dcipher = null;

	private Signature sSignature = null;

	private Signature vSignature = null;

	static {
		Security.addProvider(new BouncyCastleProvider());
	}

	public AsymmetricCrypto() {
		try {

			keypair = generatorKeyPair();
			privateKey = keypair.getPrivate();
			publicKey = keypair.getPublic();

			ecipher = Cipher.getInstance(CRYPTO_FORM);
			ecipher.init(Cipher.ENCRYPT_MODE, publicKey);

			dcipher = Cipher.getInstance(CRYPTO_FORM);
			dcipher.init(Cipher.DECRYPT_MODE, privateKey);

			sSignature = Signature.getInstance(SIGNATURE_FORM);
			sSignature.initSign(privateKey);

			vSignature = Signature.getInstance(SIGNATURE_FORM);
			vSignature.initVerify(publicKey);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成密钥对
	 * 
	 * @return
	 * @throws Exception
	 */
	private KeyPair generatorKeyPair() throws Exception {
		KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ARITHMETIC_RSA);
		keyGen.initialize(KEY_SIZE);
		return keyGen.genKeyPair();
	}

	/**
	 * 加密
	 * 
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public byte[] encrypt(byte[] data) throws Exception {

		int blockSize = ecipher.getBlockSize();
		int outputSize = ecipher.getOutputSize(data.length);
		int leavedSize = data.length % blockSize;
		int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
				: data.length / blockSize;
		byte[] encrypt = new byte[outputSize * blocksSize];
		int i = 0;
		while (data.length - i * blockSize > 0) {
			if (data.length - i * blockSize > blockSize)
				ecipher.doFinal(data, i * blockSize, blockSize, encrypt, i
						* outputSize);
			else
				ecipher.doFinal(data, i * blockSize, data.length - i
						* blockSize, encrypt, i * outputSize);
			i++;
		}

		return encrypt;
	}

	/**
	 * 解密
	 * 
	 * @param encryptData
	 * @return
	 * @throws Exception
	 */
	public byte[] decrypt(byte[] encryptData) throws Exception {

		byte[] decodeEncryptData = encryptData;

		int blockSize = dcipher.getBlockSize();
		ByteArrayOutputStream decrypt = new ByteArrayOutputStream(64);
		int j = 0;

		while (decodeEncryptData.length - j * blockSize > 0) {
			decrypt.write(dcipher.doFinal(decodeEncryptData, j * blockSize,
					blockSize));
			j++;
		}
		return decrypt.toByteArray();

	}

	/**
	 * 签名
	 * 
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public byte[] signature(byte[] data) throws Exception {
		sSignature.update(data);
		return sSignature.sign();
	}

	/**
	 * 验证
	 * 
	 * @param data
	 * @param publicKey
	 * @param signData
	 * @return
	 * @throws Exception
	 */
	public boolean verify(byte[] buffer, byte[] signData)
			throws Exception {
		vSignature.update(buffer);
		return vSignature.verify(signData);
	}

	public static void main(String[] args) throws Exception {

		AsymmetricCrypto cryptor = new AsymmetricCrypto();

		byte[] bytes = "abc".getBytes();

		byte[] encBytes = cryptor.encrypt(bytes);// 加密

		byte[] sin = cryptor.signature(encBytes);// 签名

		System.out.println(cryptor.verify(encBytes, sin));// 验证

		byte[] denc = cryptor.decrypt(encBytes);// 解密

		System.out.println(new String(denc));

	}
}